﻿using Common;
using SLAssetSystem;
using SLBehaviourSystem;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

namespace SLUISystem
{
    public class BehaviourWindow : EditorWindow
    {
        [MenuItem("CustomTools/Behaviour/BehaviourWindow")]
        static void OpenWindow()
        {
            BehaviourWindow demoWindow = GetWindow(typeof(BehaviourWindow)) as BehaviourWindow;
            demoWindow.titleContent = new GUIContent("编辑器Demo");
            demoWindow.wantsMouseMove = true;
            demoWindow.minSize = new Vector2(600f, 500f);
            DontDestroyOnLoad(demoWindow);
        }

        private Rect ToolBarRect;
        private Rect PropertyToolBarRect;
        private Rect PropertyBoxRect;
        private Rect GraphRect;
        private Vector2 GraphScrollPosition = new Vector2(10000f, 10000f);
        private Vector2 GraphOffset;
        private Vector2 GraphScrollSize = new Vector2(20000f, 20000f);

        private Vector2 CurrentMousePosition;
        private float GraphZoom = 1;

        BehaviourEditorMenu RightClickBlockMenu;

        BehaviourEditorNode curRootNode;
        BehaviourEditorNode predictNode;
        int predictIndex;


        public BehaviourEditorNode CurSelectNode
        {
            get
            {
                return curSelectNode;
            }
            set
            {
                Debug.Log("CurSelectNode Set");
                curSelectNode = value;
            }
        }

        private BehaviourEditorNode curSelectNode;

        public BehaviourTree runTimeTree;

        public Dictionary<BehaviourNodeType,string[]> nodeTypes = new Dictionary<BehaviourNodeType, string[]>();
        public Dictionary<BehaviourNodeType,string[]> componentTypes = new Dictionary<BehaviourNodeType, string[]>();


        private EditorRecordableList<Key2ValueJsonData> peopertyReorderList;

        private void OnEnable()
        {
            peopertyReorderList = new EditorRecordableList<Key2ValueJsonData>((rect,data,index, isActive, isFocused) => {
                //Key2ValueJsonData element = dataList[index];
                float height = 20;
                Rect keyRect = new Rect(rect)
                {
                    y = rect.y +5,
                    height = height,
                };
                Rect valueRect = new Rect(rect)
                {
                    y = rect.y + height + 5,
                    height = height,
                };
                
                data.Key= EditorGUI.TextField(keyRect, "Key", data.Key); 
                data.Value = EditorGUI.TextField(valueRect, "Value", data.Value);
                //element. = EditorGUI.TextField(keyRect, keyProperty.stringValue);
                //valueProperty.stringValue = EditorGUI.TextField(valueRect, valueProperty.stringValue);
            });
            peopertyReorderList.SetItemHeight(50);
            InitNode(BehaviourNodeType.Composite);
            InitNode(BehaviourNodeType.Action);
            InitComponents(BehaviourNodeType.Action);
            InitNode(BehaviourNodeType.Condition);
            InitComponents(BehaviourNodeType.Condition);
            InitNode(BehaviourNodeType.Decorator);
        }

        private void InitNode(BehaviourNodeType nodeType)
        {
            var keys = BehaviourNodeConfig.NodeDict[nodeType].Keys;
            string[] composites = new string[keys.Count];
            keys.CopyTo(composites, 0);
            nodeTypes.Add(nodeType, composites);
        }

        private void InitComponents(BehaviourNodeType nodeType)
        {
            var keys = BehaviourComponentConfig.ComponentDict[nodeType].Keys;
            string[] components = new string[keys.Count];
            keys.CopyTo(components, 0);
            componentTypes.Add(nodeType, components);
        }


        void InitSize()
        {
            ToolBarRect = new Rect(EditorWindowConfig.PropertyBoxWidth, 0f, (Screen.width - EditorWindowConfig.PropertyBoxWidth), EditorWindowConfig.ToolBarHeight);
            PropertyToolBarRect = new Rect(0f, 0f, EditorWindowConfig.PropertyBoxWidth, EditorWindowConfig.ToolBarHeight);
            PropertyBoxRect = new Rect(0f, PropertyToolBarRect.height, EditorWindowConfig.PropertyBoxWidth, Screen.height - PropertyToolBarRect.height - EditorWindowConfig.EditorWindowTabHeight);

            GraphRect = new Rect(EditorWindowConfig.PropertyBoxWidth,
                                    EditorWindowConfig.ToolBarHeight,
                                    (Screen.width - EditorWindowConfig.PropertyBoxWidth - EditorWindowConfig.ScrollBarSize),
                                    (Screen.height - EditorWindowConfig.ToolBarHeight - EditorWindowConfig.EditorWindowTabHeight - EditorWindowConfig.ScrollBarSize));
        }

        private void OnGUI()
        {
            if (Selection.activeObject)
            {
                GameObject go = Selection.activeObject as GameObject;
                if (go)
                {
                    IBehaviourAgent agent = go.GetComponent<IBehaviourAgent>();
                    if (agent != null)
                    {
                        BehaviourTree temptree = agent.Tree;
                        if (temptree != null && temptree.Tree != null)
                        {
                            if ((runTimeTree != null && runTimeTree.Tree != null && temptree.Tree != runTimeTree.Tree)
                                || runTimeTree == null)
                            {
                                runTimeTree = temptree;
                                curRootNode = BehaviourEditorNode.Create(this, runTimeTree.Tree);
                            }
                        }
                    }
                }
            }

            InitSize();
            CurrentMousePosition = Event.current.mousePosition;
            HandleInputEvents();
            DrawToolBar();
            DrawProperties();
            DrawGraphArea();
        }

        private void Update()
        {
            Repaint();
        }

        private void DrawToolBar()
        {
            GUILayout.BeginArea(ToolBarRect, EditorStyles.toolbar);
            GUILayout.BeginHorizontal();
            if (GUILayout.Button("Load", EditorStyles.toolbarButton, GUILayout.Width(80f)))
            {
                string path = EditorUtility.OpenFilePanel("选择文件", Application.dataPath + "/Resources/" + AssetPaths.BehaviourTreeConfigPath, "json");
                path = AssetPaths.GetResourcesPath(path);
                path = AssetPaths.GetFileWithoutExtension(path);
                JsonData jsonData = AssetSystem.Inst.LoadResAsset<JsonData>(path, AssetType.Json);
                BehaviourTreeJsonData treeJsonData = jsonData.GetData<BehaviourTreeJsonData>();
                Debug.Log(JsonUtility.ToJson(treeJsonData));
                curRootNode = BehaviourEditorNode.Create(this, treeJsonData);
                ReCode();
                ReLayout();
            }

            if (GUILayout.Button("Save", EditorStyles.toolbarButton, GUILayout.Width(80f)))
            {
                if (curRootNode != null)
                {
                    BehaviourTreeJsonData treeJsonData = new BehaviourTreeJsonData();
                    curRootNode.Save(treeJsonData);
                    treeJsonData.Nodes.Sort((a, b) => {
                        return a.Id.CompareTo(b.Id);
                    });
                    string path = EditorUtility.OpenFilePanel("选择文件", Application.dataPath + "/Resources/" + AssetPaths.BehaviourTreeConfigPath, "json");
                    File.WriteAllText(path, JsonUtility.ToJson(treeJsonData));
                    AssetDatabase.Refresh();
                }

            }

            GUILayout.FlexibleSpace();

            if (GUILayout.Button("ReLayout", EditorStyles.toolbarButton, GUILayout.Width(80f)))
            {
                if (curRootNode != null)
                {
                    curRootNode.ReLayout();
                }
            }

            if (GUILayout.Button("ReCode", EditorStyles.toolbarButton, GUILayout.Width(80f)))
            {
                if (curRootNode != null)
                {
                    BehaviourEditorNode.IdIndex = 0;
                    curRootNode.ReCode();
                }
            }
            GUILayout.EndHorizontal();
            GUILayout.EndArea();
        }

        private void DrawProperties()
        {
            GUILayout.BeginArea(PropertyToolBarRect, EditorStyles.toolbar);
            GUILayout.BeginHorizontal();
            if (GUILayout.Button("RecreateNodeType", EditorStyles.toolbarButton, GUILayout.Width(160f)))
            {
                BehaviourConfigUtils.CreateNodeConfig();
            }

            if (GUILayout.Button("RecreateComponentType", EditorStyles.toolbarButton, GUILayout.Width(160f)))
            {
                BehaviourConfigUtils.CreateComponentConfig();
            }
            GUILayout.EndHorizontal();
            GUILayout.EndArea();

            GUILayout.BeginArea(PropertyBoxRect);

            if (CurSelectNode != null)
            {
                CurSelectNode.Data.Des = EditorLayoutHelper.TextInput("Des:", CurSelectNode.Data.Des);
                GUILayout.Label("ID:" + CurSelectNode.Data.Id.ToString());
                CurSelectNode.Data.NodeType = (BehaviourNodeType)EditorLayoutHelper.EnumPop("BehaviourNodeType:", CurSelectNode.Data.NodeType);
                if (BehaviourNodeType.Composite == CurSelectNode.Data.NodeType)
                {
                    CurSelectNode.Data.InterrupteType = (BehaviourInterruptType)EditorLayoutHelper.EnumPop("BehaviourInteruptType:", CurSelectNode.Data.InterrupteType);
                }

                

                if (BehaviourNodeType.Composite == CurSelectNode.Data.NodeType|| BehaviourNodeType.Decorator == CurSelectNode.Data.NodeType)
                {
                    int selectIndex = 0;
                    for (int i = 0; i < nodeTypes[CurSelectNode.Data.NodeType].Length; i++)
                    {
                        if (CurSelectNode.Data.RuntimeNodeType == nodeTypes[CurSelectNode.Data.NodeType][i])
                        {
                            selectIndex = i;
                            break;
                        }
                    }
                    selectIndex = EditorLayoutHelper.Popup("CompositeType:", selectIndex, nodeTypes[CurSelectNode.Data.NodeType]);

                    string runtimeNodeType = nodeTypes[CurSelectNode.Data.NodeType][selectIndex];
                    CurSelectNode.Data.RuntimeNodeType = runtimeNodeType;
                }
                else
                {
                    CurSelectNode.Data.ExcuteType= (BehaviourExcuteType)EditorLayoutHelper.EnumPop("BehaviourExcuteType:", CurSelectNode.Data.ExcuteType);
                    CurSelectNode.Data.RuntimeNodeType = nodeTypes[CurSelectNode.Data.NodeType][0];
                    GUILayout.Label("RuntimeNodeType:"+ CurSelectNode.Data.RuntimeNodeType);
                    int selectIndex = 0;
                    for (int i = 0; i < componentTypes[CurSelectNode.Data.NodeType].Length; i++)
                    {
                        if (CurSelectNode.Data.RuntimeComponentType == componentTypes[CurSelectNode.Data.NodeType][i])
                        {
                            selectIndex = i;
                            break;
                        }
                    }
                    selectIndex = EditorLayoutHelper.Popup("ComponentType:", selectIndex, componentTypes[CurSelectNode.Data.NodeType]);

                    string runtimeComponentType = componentTypes[CurSelectNode.Data.NodeType][selectIndex];
                    CurSelectNode.Data.RuntimeComponentType = runtimeComponentType;

                    List<Key2ValueJsonData> datas = CurSelectNode.Data.Datas;
                    if (BehaciourEditorDefines.ComponentArgs.ContainsKey(runtimeComponentType))
                    {
                        bool isContain = false;
                        foreach (var item in BehaciourEditorDefines.ComponentArgs[runtimeComponentType])
                        {
                            for (int i = 0; i < datas.Count; i++)
                            {
                                if (item.Key == datas[i].Key)
                                {
                                    datas[i].Value = EditorLayoutHelper.TextInput(item.Key, datas[i].Value);
                                    isContain = true;
                                    break;
                                }
                            }
                            if (!isContain)
                            {
                                datas.Add(new Key2ValueJsonData());
                                datas[datas.Count - 1].Key = item.Key;
                                datas[datas.Count - 1].Value = EditorLayoutHelper.TextInput(item.Key, datas[datas.Count - 1].Value);
                            }
                        }
                    }
                    else
                    {
                        peopertyReorderList.SetData(datas);
                        peopertyReorderList.Draw();
                    }
                }
            }
            GUILayout.EndArea();
        }

        private void DrawGraphArea()
        {
            Vector2 vector = GUI.BeginScrollView(new Rect(GraphRect.x, GraphRect.y, GraphRect.width + EditorWindowConfig.ScrollBarSize, GraphRect.height + EditorWindowConfig.ScrollBarSize), GraphScrollPosition, new Rect(GraphScrollPosition.x, GraphScrollPosition.y, GraphScrollSize.x, GraphScrollSize.y), true, true);
            if (vector != GraphScrollPosition && Event.current.type != EventType.DragUpdated && Event.current.type != EventType.Ignore)
            {
                //mGraphOffset -= (vector - GraphScrollPosition) / mGraphZoom;
                GraphScrollPosition = vector;
                //mGraphDesigner.graphDirty();
            }
            GUI.EndScrollView();

            GUI.Box(GraphRect, "", EditorWindowConfig.GraphBackgroundGUIStyle);

            EditorZoomArea.Begin(GraphRect, GraphZoom);
            //GUI.Label(rect, "", m_Selected ? BTreeEditorUtility.TaskSelectedGUIStyle : BTreeEditorUtility.TaskGUIStyle);
            if (curRootNode != null)
            {
                BehaviourTreeEditorDrawer.DrawNode(curRootNode, GraphScrollPosition);
            }

            EditorZoomArea.End();
        }

        private void HandleInputEvents()
        {
            if (EditorApplication.isCompiling) return;

            Event e = Event.current;
            Vector2 point;
            switch (e.type)
            {
                case EventType.MouseDown:
                    if (IsMousePositionInRect(GraphRect, out point))
                    {
                        if (curRootNode != null)
                        {
                            CurSelectNode = curRootNode.CheckClickAndChild(point);
                            //if (curSelectNode != null && curSelectNode.Data.NodeComponentType == BehaviourComponentType.TreeRefrence)
                            //{
                            //    TreeRefrenceNode treeRefrence = runTimeTree.NodeDict[curSelectNode.Data.Id] as TreeRefrenceNode;
                            //    runTimeTree = treeRefrence.Tree;
                            //    curRootNode = BehaviourEditorNode.Create(this, runTimeTree.Tree);
                            //}
                        }
                        e.Use();
                    }
                    break;
                case EventType.MouseUp:
                    if (e.button == 0)
                    {
                        if (predictNode!=null)
                        {

                            curSelectNode.Parent.Childs.Remove(curSelectNode);
                            curSelectNode.Parent.Data.ChildIds.Remove(curSelectNode.Data.Id);
                            curSelectNode.Parent.CheckLayout();
                            
                            Debug.Log(predictIndex);
                            if (predictNode== curSelectNode.Parent)
                            {
                                if (predictIndex> predictNode.Childs.Count)
                                {
                                    predictIndex = predictNode.Childs.Count;
                                }
                                
                            }
                            predictNode.Childs.Insert(predictIndex, curSelectNode);
                            predictNode.Data.ChildIds.Insert(predictIndex, curSelectNode.Data.Id);
                            curSelectNode.Parent = predictNode;
                            curSelectNode.CheckLayout();
                            predictNode.CheckLayout();

                            predictNode = null;
                        }

                        ReCode();
                        ReLayout();
                    }
                    else if (e.button == 1)
                    {
                        Debug.Log("鼠标右键键抬起");
                        if (IsMousePositionInRect(GraphRect, out point))
                        {
                            if (curRootNode != null)
                            {
                                if (CurSelectNode!=null)
                                {
                                    if (RightClickBlockMenu == null)
                                    {
                                        RightClickBlockMenu = new BehaviourEditorMenu(this);
                                    }
                                    RightClickBlockMenu.ShowAsContext();
                                }
                            }
                            Debug.Log("鼠标右键键点击  " + IsMousePositionInRect(GraphRect, out point) + "  " + point);
                        }
                        e.Use();
                    }
                    else if (e.button == 2)
                    {
                        Debug.Log("鼠标中键键抬起");
                    }
                    break;
                case EventType.MouseMove:
                    if (e.button == 0)
                    {
                        Debug.Log("鼠标左键移动");
                    }
                    else if (e.button == 1)
                    {
                        Debug.Log("鼠标右键键移动");
                    }
                    else if (e.button == 2)
                    {
                        Debug.Log("鼠标中键键移动");
                    }
                    break;
                case EventType.MouseDrag:
                    if (e.button == 0)
                    {
                        if (IsMousePositionInRect(GraphRect, out point))
                        {
                            if (curRootNode!=null)
                            {
                                if (curRootNode.CheckDrag(CurSelectNode, point, e.delta))
                                {
                                    Repaint();
                                }
                                predictIndex = curRootNode.CheckPredictNode(out predictNode);
                            }

                            e.Use();
                        }


                    }
                    else if (e.button == 1)
                    {
                        Debug.Log("鼠标右键键拖动");
                    }
                    else if (e.button == 2)
                    {
                        Debug.Log("鼠标中键键拖动");
                        if (IsMousePositionInRect(GraphRect, out point))
                        {
                            GraphScrollPosition -= e.delta;
                            e.Use();
                        }

                    }
                    break;
                case EventType.KeyDown:
                    break;
                case EventType.KeyUp:
                    break;
                case EventType.ScrollWheel:
                    Debug.Log("鼠标中键滚动");
                    GraphZoom += e.delta.y * 0.01f;
                    GraphZoom = Mathf.Clamp(GraphZoom, 1, 5);
                    e.Use();
                    break;
                case EventType.Repaint:
                    break;
                case EventType.Layout:
                    break;
                case EventType.DragUpdated:
                    break;
                case EventType.DragPerform:
                    break;
                case EventType.DragExited:
                    break;
                case EventType.Ignore:
                    break;
                case EventType.Used:
                    break;
                case EventType.ValidateCommand:
                    break;
                case EventType.ExecuteCommand:
                    break;
                case EventType.ContextClick:
                    break;
                default:
                    break;
            }
        }

        private bool IsMousePositionInRect(Rect rect, out Vector2 mousePosition)
        {
            mousePosition = CurrentMousePosition;
            if (!rect.Contains(mousePosition))
            {
                return false;
            }
            mousePosition -= new Vector2(rect.xMin, rect.yMin);
            //mousePosition /= mGraphZoom;
            return true;
        }

        public void ReCode()
        {
            if (curRootNode != null)
            {
                BehaviourEditorNode.IdIndex = 0;
                curRootNode.ReCode();
            }
        }

        public void ReLayout()
        {
            if (curRootNode != null)
            {
                curRootNode.ReLayout();
            }
        }
    }
}

